home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / MTMDI.PAK / README.TXT < prev    next >
Text File  |  1997-05-06  |  11KB  |  219 lines

  1.     This is a part of the Microsoft Foundation Classes C++ library.
  2.     Copyright (C) 1994-1995 Microsoft Corporation
  3.     All rights reserved.
  4.  
  5.     This source code is only intended as a supplement to the
  6.     Microsoft Foundation Classes Reference and related
  7.     electronic documentation provided with the library.
  8.     See these sources for detailed information regarding the
  9.     Microsoft Foundation Classes product.
  10.  
  11.  
  12. -------------------------------------------------------
  13. MTMDI Sample Microsoft Foundation Classes Application
  14. -------------------------------------------------------
  15.  
  16. The MTMDI sample illustrates an MFC user-interface thread, where user
  17. interface events are processed in a thread separate from the main
  18. application thread.  This sample is a modified version of the single
  19. thread MDI sample.
  20.  
  21. The MTMDI sample does not claim a strong rationale for putting the
  22. bouncing ball window in a separate thread.  An end-user would not be
  23. able to detect the difference between the MDI and MTMDI samples on a
  24. single processor machine.  Even on a multi-processor machine, the
  25. end-user would not be able to detect the difference given that the
  26. ball movement is based on a window timer.
  27.  
  28. Further, the MTMDI sample does not claim a strong rationale for using
  29. an MFC worker thread instead of an MFC user-interface thread.  MFC worker
  30. threads generally are easier to use and more appropriate than user-interface
  31. threads for tasks that do not involve processing of user interface events.
  32. The drawing of the bouncing ball could have been implemented in
  33. a worker thread instead of a user-interface thread, if some technique
  34. other than window timers were used to advance the ball.  The use of the
  35. window timer in a separate thread requires a message pump; therefore
  36. the separate thread must be a user-interface thread instead of a worker
  37. thread.  To add slightly more justification for using a user-interface
  38. thread, the MTMDI sample includes one additional user-interface feature
  39. not in the MDI sample:  you can click anywhere in the bounce window to
  40. immediately change the position of the moving ball.
  41.  
  42. Although the MDI sample does not claim a strong rationale for using
  43. threads, it nevertheless does illustrate techniques for implementing an
  44. MFC user-interface thread.  The remainder of this readme describes
  45. the differences between the implementation of the single thread MDI
  46. application and the multiple thread MTMDI application.  These differences
  47. illustrate that it is more difficult to implement an application with
  48. a user-interface thread than a corresponding application that executes
  49. in a single thread.  This should be a warning that you should not use
  50. user-interface threads unless you have good reasons.
  51.  
  52. The overall differences between the implementation of the MDI and MTMDI
  53. samples are these:
  54.  
  55. 1.  The CBounceWnd window runs in a separate user-interface thread
  56.     in the MTMDI application.
  57.  
  58. 2.  In the MDI sample, CBounceWnd is derived from CMDIChildWnd.  In the
  59.     MTMDI sample, CBounceWnd is derived from CWnd, and a CBounceWnd
  60.     window is a child of the MDI child window.  In the MTMDI sample,
  61.     the CBounceWnd child window fills exactly the client area of the
  62.     parent MDI child window (a CMDIChildBounceWnd).
  63.  
  64. 3.  In the MDI sample, normal MFC command routing and command user-
  65.     interface initialization are used for menu commands associated with
  66.     the bounce window.  In the MTMDI sample, the MDI child window's
  67.     OnCmdMsg function is overridden in order to send the OnCmdMsg
  68.     parameters via SendMessage to the CBounceWnd executing in the
  69.     separate thread.  In general, SendMessage typically needs to be
  70.     used us to make calls from a window in one thread to a window in
  71.     another thread in an MFC application.
  72.  
  73. Note:  The Hello window is left in the main application thread.
  74.        Implementing the Bounce window in a separate thread is sufficient
  75.        to illustrate the MFC multithread techniques.
  76.  
  77. This MTMDI sample does not directly illustrate a view running in a separate
  78. thread, because MTMDI and the original MDI sample do not use MFC's
  79. document/view architecture.  Still, the design of MTMDI can be applied
  80. to an application where you might want the view to run in a separate thread.
  81. In general, you cannot successfully implement member functions of a CView
  82. to run in a separate thread, because the MFC document/view architecture
  83. relies on thread local storage (TLC) for some of the data that coordinates
  84. documents and views.  However, you can apply the design of MTMDI by
  85. implementing a child window of the CView window, and processing user-
  86. interface events of this child window in a separate thread.
  87.  
  88. The design of MTMDI is summarized below.  For additional details, see
  89. source code comments.
  90.  
  91.  
  92. =================
  93. CWinThread object
  94. =================
  95.  
  96. The thread object for the bouncing ball window is implemented in
  97. a CWinThread-derived class, CBounceThread, in mtbounce.cpp.
  98.  
  99. Beginning the user-interface thread
  100. -----------------------------------
  101. The overridden CMDIChildBounceWnd::OnCreate begins the thread for
  102. the bouncing ball.   There are two ways to begin an MFC user-interface
  103. thread:  (1) call AfxBeginThread, passing the CRuntimeClass of the
  104. CWinThread-derived class; or (2) implement two-stage construction of
  105. the CWinThread-derived object by new'ing it and then calling
  106. CWinThread::CreateThread.  We use the second method because it offers
  107. the easiest way to pass the HWND of the CMainFrame window to the
  108. thread, which needs the parent HWND to create the child window.
  109. We simply pass the HWND to the CBounceThread constructor.
  110.  
  111. An alternative method is:
  112. - call AfxBeginThread with a CREATE_SUSPENDED parameter;
  113. - pass the parent HWND via a new CBounceThread::SetParentWnd function;
  114.   or make the CBounceThread::m_hwndParent member variable public and
  115.   set it directly; and then
  116. - call CWinThread::ResumeThread.
  117.  
  118. Thread instance initialization
  119. ------------------------------
  120. CWinThread::InitInstance is the only member function that must be
  121. overridden for a user-interface thread.  The implementation of
  122. CBounceThread::InitInstance is typical in that it creates (using
  123. CWnd::Create) the window that processes messages in the separate thread.
  124.  
  125. Terminating the user-interface thread
  126. -------------------------------------
  127. The easiest way to terminate a user-interface thread is to rely on
  128. automatic termination of the thread when the main window associated with
  129. the thread is destroyed.  The only thing you need to do to implement
  130. such automatic thread termination is to set the CWinThread::m_pMainWnd
  131. to the main window.  This is illustrated in CBounceThread::InitInstance.
  132. The default CWnd::OnNcDestroy handler checks whether the window being
  133. destroyed is the thread's m_pMainWnd and, if so, terminates the thread,
  134. provided it isn't the main application thread.
  135.  
  136. Unless you change the default TRUE value of CWinThread::m_bAutoDelete,
  137. the framework will automatically delete the CWinThread object when the
  138. thread terminates.
  139.  
  140. Avoiding memory leak detection of CWinThread object
  141. ---------------------------------------------------
  142. When the application terminates, it destroys each window in the window
  143. hierarchy, and then, in debug mode, checks for memory leaks.
  144. It is possible that the application will falsely detect a memory leak of the
  145. CWinThread object before the user-interface thread has had a chance to
  146. automatically terminate.  The reported memory leak is false because
  147. eventually the CWinThread object will be automatically destroyed anyway.
  148.  
  149. Nevertheless, the dumping of memory leak information can be disconcerting.
  150. To avoid this, we use a "bounce thread killed" event.  The CBounceThread
  151. delete operator sets the event.  The main application waits for this event
  152. before terminating.  It is better to set the event in the delete operator
  153. rather than in the CBounceThread destructor, because it is remotely possible
  154. that the application might terminate (and report a memory leak) between
  155. the time the CBounceThread destructor completes and the time that the
  156. CBounceThread object is actually deleted.
  157.  
  158.  
  159. ================
  160. MDI child window
  161. ================
  162. In the original MDI sample, the CBounceWnd was a CMDIChildWnd.  It
  163. handled the Color and Speed menu commands.  In the MTMDI sample, the
  164. CBounceWnd is a CWnd; and the CBounceWnd window is a child of the
  165. MDI child window.  There still needs to be a CMDIChildWnd class.
  166. It is named CMDIChildBounceWnd, and is implemented in bounce.cpp,
  167. where CBounceWnd is also implemented.
  168.  
  169.  
  170. Creation of the MDI child window
  171. --------------------------------
  172. As in the original MDI sample, the CMainFrame::OnBounce handler
  173. creates the CMDIChildWnd when the user requests a new bouncing ball
  174. window.  The implementation of CMDIChildBounceWnd::Create borrows
  175. half of the implementation of the original MDI sample's
  176. CBounceWnd::Create.  The half borrowed is the implementation of the
  177. shared menu.  The other half, the window class registration, is
  178. left in the implementation of CBounceWnd::Create.
  179.  
  180. The overridden CMDIChildBounce::Create also creates the bounce thread.
  181.  
  182. Delegation of commands and command user-interface initialization
  183. ----------------------------------------------------------------
  184. CMDIChildWnd delegates commands and command user-interface initialization
  185. to the child CBounceWnd.  One laborious way to do this is delegate each
  186. command on a per command basis.  An easier but more sophisticated way to
  187. do this is to override OnCmdMsg and pass the OnCmdMsg parameters to the
  188. CBounceWnd in a structure via SendMessage.  For more details, see source
  189. code comments for CMDIChildBounceWnd::OnCmdMsg.
  190.  
  191.  
  192. ============================
  193. User-interface thread window
  194. ============================
  195.  
  196. The bouncing ball window is implemented in a CWnd-derived class,
  197. CBounceWnd, in bounce.cpp.  It reuses almost all of the CBounceWnd code
  198. in the original MDI sample, where the CBounceWnd was a CMDIChildWnd instead
  199. of a plain CWnd.
  200.  
  201.  
  202. Creation of the bouncing ball window
  203. ------------------------------------
  204. CBounceThread::InitInstance calls the CBounceWnd-override of CWnd::Create
  205. to create the window.  The implementation of CBounceWnd::Create is borrowed
  206. from the original MDI sample's implementation, less the shared menu
  207. initialization code that is now in CMDIChildBounceWnd::Create.
  208.  
  209. Command handling and command user-interface initialization
  210. ----------------------------------------------------------
  211. All commands and command user-interface initialization is delegated by
  212. the CMDIChildBounceWnd object to the CBounceWnd object.
  213. CMDIChildBounceWnd::OnCmdMsg sends a user-defined WM_USER_ONCMDMSG message
  214. to the CBounceWnd window.  This message contains all of the information
  215. originally passed to CMDIChildBounceWnd::OnCmdMsg.
  216. The CBounceWnd handler for WM_USER_ONCMDMSG, named OnDelegatedCmdMsg,
  217. unpacks the COnCmdMsg struct passed via the lParam, and calls the default
  218. CWnd::OnCmdMsg for the CBounceWnd object.
  219.